﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace iNet.Media.Xmp
{
	/// <summary>
	/// XmpPropertyValue 工廠元件。
	/// </summary>
	public interface IXmpPropertyValueFactory
	{
		/// <summary>
		/// 嘗試根據指定的 XML 節點建立對應的 XmpPropertyValue。
		/// </summary>
		/// <param name="valueNode">指定的 XML 節點。</param>
		/// <param name="value">建立的 XmpPropertyValue。</param>
		/// <returns>True 表示建立成功，False 表示建立失敗。</returns>
		bool TryCreate(XmlNode valueNode, out XmpPropertyValue value);
	}
	#region ArrayXmpPropertyValueFactory
	/// <summary>
	/// ArrayXmpPropertyValue 工廠元件。
	/// </summary>
	public class ArrayXmpPropertyValueFactory : XmpPropertyValueFactory
	{
		#region 建構子
		/// <summary>
		/// 初始化新的 ArrayXmpPropertyValueFactory 執行個體。
		/// </summary>
		public ArrayXmpPropertyValueFactory()
		{ }
		#endregion
		#region TryCreateCore
		protected override bool TryCreateCore(XmlNode valueNode, out XmpPropertyValue value)
		{
			//建立
			if (valueNode.NamespaceURI == "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
			{
				XmpArrayType? arrayType;
				switch (valueNode.LocalName)
				{
					case "Bag":
						arrayType = XmpArrayType.Unordered;
						break;
					case "Seq":
						arrayType = XmpArrayType.Ordered;
						break;
					case "Alt":
						arrayType = XmpArrayType.Alternative;
						break;
					default:
						arrayType = null;
						break;
				}
				if (arrayType != null)
				{
					ArrayXmpPropertyValue array = new ArrayXmpPropertyValue(arrayType.Value);
					XmlNode itemNode = valueNode.FirstChild;
					while (itemNode != null)
					{
						if (itemNode.LocalName == "li" && itemNode.NamespaceURI == "http://www.w3.org/1999/02/22-rdf-syntax-ns#" && itemNode.ChildNodes.Count == 1)
						{
							//建立值
							XmpPropertyValue itemValue = XmpPropertyValue.Create(itemNode.FirstChild);

							//取得 xml:lang Qualifier
							XmlAttribute attr = itemNode.Attributes["xml:lang"];
							if (attr != null)
								itemValue.Qualifiers.Add(new XmpPropertyQualifier(null, "xml:lang", attr.Value));

							//加入集合
							array.Items.Add(itemValue);
						}
						itemNode = itemNode.NextSibling;
					}
					value = array;
					return true;
				}
			}

			//轉換失敗
			value = null;
			return false;
		}
		#endregion
	}
	#endregion
	#region BooleanXmpPropertyValueFactory
	/// <summary>
	/// BooleanXmpPropertyValue 工廠元件。
	/// </summary>
	public class BooleanXmpPropertyValueFactory : XmpPropertyValueFactory
	{
		#region 建構子
		/// <summary>
		/// 初始化新的 BooleanXmpPropertyValueFactory 執行個體。
		/// </summary>
		public BooleanXmpPropertyValueFactory()
		{ }
		#endregion
		#region TryCreateCore
		protected override bool TryCreateCore(XmlNode valueNode, out XmpPropertyValue value)
		{
			//建立
			bool boolValue;
			if (valueNode is XmlText && bool.TryParse(valueNode.Value, out boolValue))
			{
				value = new BooleanXmpPropertyValue(boolValue);
				return true;
			}

			//轉換失敗
			value = null;
			return false;
		}
		#endregion
	}
	#endregion
	#region DateXmpPropertyValueFactory
	/// <summary>
	/// DateXmpPropertyValue 工廠元件。
	/// </summary>
	public class DateXmpPropertyValueFactory : XmpPropertyValueFactory
	{
		#region 建構子
		/// <summary>
		/// 初始化新的 DateXmpPropertyValueFactory 執行個體。
		/// </summary>
		public DateXmpPropertyValueFactory()
		{ }
		#endregion
		#region TryCreateCore
		protected override bool TryCreateCore(XmlNode valueNode, out XmpPropertyValue value)
		{
			//建立
			DateTime dateTime;
			if (valueNode is XmlText && DateTime.TryParse(valueNode.Value, out dateTime))
			{
				value = new DateXmpPropertyValue(dateTime);
				return true;
			}

			//轉換失敗
			value = null;
			return false;
		}
		#endregion
	}
	#endregion
	#region IntegerXmpPropertyValueFactory
	/// <summary>
	/// IntegerXmpPropertyValue 工廠元件。
	/// </summary>
	public class IntegerXmpPropertyValueFactory : XmpPropertyValueFactory
	{
		#region 建構子
		/// <summary>
		/// 初始化新的 IntegerXmpPropertyValueFactory 執行個體。
		/// </summary>
		public IntegerXmpPropertyValueFactory()
		{ }
		#endregion
		#region TryCreateCore
		protected override bool TryCreateCore(XmlNode valueNode, out XmpPropertyValue value)
		{
			//建立
			long intValue;
			if (valueNode is XmlText && long.TryParse(valueNode.Value, out intValue))
			{
				value = new IntegerXmpPropertyValue(intValue);
				return true;
			}

			//轉換失敗
			value = null;
			return false;
		}
		#endregion
	}
	#endregion
	#region RationalXmpPropertyValueFactory
	/// <summary>
	/// RationalXmpPropertyValue 工廠元件。
	/// </summary>
	public class RationalXmpPropertyValueFactory : XmpPropertyValueFactory
	{
		#region 建構子
		/// <summary>
		/// 初始化新的 RationalXmpPropertyValueFactory 執行個體。
		/// </summary>
		public RationalXmpPropertyValueFactory()
		{ }
		#endregion
		#region TryCreateCore
		protected override bool TryCreateCore(XmlNode valueNode, out XmpPropertyValue value)
		{
			//建立
			Rational rational;
			if (valueNode is XmlText && Rational.TryParse(valueNode.Value, out rational))
			{
				value = new RationalXmpPropertyValue(rational);
				return true;
			}

			//轉換失敗
			value = null;
			return false;
		}
		#endregion
	}
	#endregion
	#region RealXmpPropertyValueFactory
	/// <summary>
	/// RealXmpPropertyValue 工廠元件。
	/// </summary>
	public class RealXmpPropertyValueFactory : XmpPropertyValueFactory
	{
		#region 建構子
		/// <summary>
		/// 初始化新的 RealXmpPropertyValueFactory 執行個體。
		/// </summary>
		public RealXmpPropertyValueFactory()
		{ }
		#endregion
		#region TryCreateCore
		protected override bool TryCreateCore(XmlNode valueNode, out XmpPropertyValue value)
		{
			//建立
			double doubleValue;
			if (valueNode is XmlText && double.TryParse(valueNode.Value, out doubleValue))
			{
				value = new RealXmpPropertyValue(doubleValue);
				return true;
			}

			//轉換失敗
			value = null;
			return false;
		}
		#endregion
	}
	#endregion
	#region StructureXmpPropertyValueFactory
	/// <summary>
	/// StructureXmpPropertyValue 工廠基底類別。
	/// </summary>
	public abstract class StructureXmpPropertyValueFactory<T> : XmpPropertyValueFactory where T : StructureXmpPropertyValue
	{
		#region 欄位
		string[] _RequiredFieldNames;
		string _SchemaNamespaceURI;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 StructureXmpPropertyValueFactory 執行個體。
		/// </summary>
		/// <param name="namespaceUri">結構所屬 Schema 的 Namespace URI。</param>
		/// <param name="requiredFieldNames">必須有值的欄位名稱。</param>
		/// <exception cref="ArgumentNullException">namespaceUri 為 Null (Visual Basic 為 Nothing)。</exception>
		protected StructureXmpPropertyValueFactory(string namespaceUri, string[] requiredFieldNames)
		{
			//確認參數
			if (namespaceUri == null)
				throw new ArgumentNullException("namespaceUri");

			//初始化
			_RequiredFieldNames = (requiredFieldNames != null ? requiredFieldNames.Clone() as string[] : new string[0]);
			_SchemaNamespaceURI = namespaceUri;
		}
		#endregion
		#region CreateValue
		/// <summary>
		/// 建立新的 StructureXmpPropertyValue 物件。
		/// </summary>
		/// <param name="schema">XMP Schema。</param>
		/// <returns>StructureXmpPropertyValue 物件。</returns>
		protected abstract T CreateValue(XmpSchema schema);
		#endregion
		#region TryCreateCore
		protected override bool TryCreateCore(XmlNode valueNode, out XmpPropertyValue value)
		{
			//初始化參數
			value = null;

			//確認是否為 rdf:Description 節點
			if (valueNode.LocalName != "Description" || valueNode.NamespaceURI != CommonXmpSchemas.RDF.NamespaceURI)
				return false;

			//檢查結構是否正確
			HashSet<string> requiredFieldNames = new HashSet<string>(_RequiredFieldNames);
			XmlNode fieldNode = valueNode.FirstChild;
			while (fieldNode != null)
			{
				//確認 Schema
				if (fieldNode.NamespaceURI != _SchemaNamespaceURI)
					return false;

				//檢查欄位名稱
				if (!fieldNode.HasChildNodes)
				{
					fieldNode = fieldNode.NextSibling;
					continue;
				}
				requiredFieldNames.Remove(fieldNode.LocalName);

				//移往下一個節點
				fieldNode = fieldNode.NextSibling;
			}

			//確認必要欄位是否都有定義
			if (requiredFieldNames.Count > 0)
				return false;

			//取出結構內容
			T structure = null;
			fieldNode = valueNode.FirstChild;
			while (fieldNode != null)
			{
				//建立物件
				if (structure == null)
				{
					XmpSchema schema = CommonXmpSchemas.GetSchemaByNamespaceURI(fieldNode.NamespaceURI);
					if (schema == null)
						schema = new XmpSchema(fieldNode.Prefix, fieldNode.NamespaceURI);
					structure = this.CreateValue(schema);
				}

				//取得欄位值
				if (!fieldNode.HasChildNodes)
				{
					fieldNode = fieldNode.NextSibling;
					continue;
				}
				try
				{
					structure.SetField(fieldNode.LocalName, XmpPropertyValue.Create(fieldNode.FirstChild));
				}
				catch (ArgumentException ex)
				{ }

				//移往下一個節點
				fieldNode = fieldNode.NextSibling;
			}
			value = structure;

			//建立完成
			return true;
		}
		#endregion
	}
	#endregion
	#region TextXmpPropertyValueFactory
	/// <summary>
	/// TextXmpPropertyValue 工廠元件。
	/// </summary>
	public class TextXmpPropertyValueFactory : XmpPropertyValueFactory
	{
		#region 建構子
		/// <summary>
		/// 初始化新的 TextXmpPropertyValueFactory 執行個體。
		/// </summary>
		public TextXmpPropertyValueFactory()
		{ }
		#endregion
		#region TryCreateCore
		protected override bool TryCreateCore(XmlNode valueNode, out XmpPropertyValue value)
		{
			//建立
			if (valueNode is XmlText)
			{
				value = new TextXmpPropertyValue(valueNode.Value);
				return true;
			}

			//轉換失敗
			value = null;
			return false;
		}
		#endregion
	}
	#endregion
	#region XmpPropertyValueFactory
	/// <summary>
	/// 實作 IXmpPropertyValueFactory 介面的基底類別。
	/// </summary>
	public abstract class XmpPropertyValueFactory : IXmpPropertyValueFactory
	{ 
		#region 建構子
		/// <summary>
		/// 初始化新的 XmpPropertyValueFactory 執行個體。
		/// </summary>
		protected XmpPropertyValueFactory()
		{ }
		#endregion
		#region TryCreate
		/// <summary>
		/// 嘗試根據指定的 XML 節點建立對應的 XmpPropertyValue。
		/// </summary>
		/// <param name="valueNode">指定的 XML 節點。</param>
		/// <param name="value">建立的 XmpPropertyValue。</param>
		/// <returns>True 表示建立成功，False 表示建立失敗。</returns>
		public bool TryCreate(XmlNode valueNode, out XmpPropertyValue value)
		{
			//確認
			if (valueNode == null)
			{
				value = null;
				return false;
			}

			//建立
			if (valueNode is XmlElement && valueNode.LocalName == "Description" && valueNode.NamespaceURI == "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
			{
				//搜尋內部結點
				XmlNode innerValueNode = null;
				XmlNode childNode = valueNode.FirstChild;
				while (childNode != null)
				{
					if (childNode.LocalName == "value" && childNode.NamespaceURI == "http://www.w3.org/1999/02/22-rdf-syntax-ns#" && childNode.ChildNodes.Count == 1)
					{
						innerValueNode = childNode.FirstChild;
						break;
					}
					childNode = childNode.NextSibling;
				}

				//建立
				if (innerValueNode == null)
					return this.TryCreateCore(valueNode, out value);
				if (!this.TryCreateCore(innerValueNode, out value) || value == null)
					return false;

				//建立 Qualifier
				Dictionary<string, XmpSchema> schemas = new Dictionary<string, XmpSchema>();
				childNode = valueNode.FirstChild;
				while (childNode != null)
				{
					if (childNode.LocalName != "value" || childNode.NamespaceURI != "http://www.w3.org/1999/02/22-rdf-syntax-ns#" && childNode.ChildNodes.Count == 1)
					{
						XmlNode node = childNode.FirstChild;
						if (node is XmlText)
						{
							//取得 XMP Schema
							XmpSchema schema;
							if (!string.IsNullOrEmpty(childNode.Prefix))
							{
								if (!schemas.TryGetValue(childNode.Prefix, out schema) || schema.NamespaceURI != childNode.NamespaceURI)
								{
									schema = new XmpSchema(childNode.Prefix, childNode.NamespaceURI);
									schemas[schema.NamespacePrefix] = schema;
								}
							}
							else
								schema = null;

							//建立 Qualifier
							XmpPropertyQualifier qualifier = new XmpPropertyQualifier(schema, childNode.LocalName, node.Value);
							value.Qualifiers.Add(qualifier);
						}
					}
					childNode = childNode.NextSibling;
				}
			}
			return this.TryCreateCore(valueNode, out value);
		}
		#endregion
		#region TryCreateCore
		/// <summary>
		/// 嘗試根據指定的 XML 節點建立對應的 XmpPropertyValue。
		/// </summary>
		/// <param name="valueNode">指定的 XML 節點。</param>
		/// <param name="value">建立的 XmpPropertyValue。</param>
		/// <returns>True 表示建立成功，False 表示建立失敗。</returns>
		protected abstract bool TryCreateCore(XmlNode valueNode, out XmpPropertyValue value);
		#endregion
	}
	#endregion
}
